class RetsController < ApplicationController
  
  include RetsHelper
  
  verify :method => :post, :render => {:text => "405 HTTP POST required", :status => :method_not_allowed}, :add_headers => {"Allow" => "POST"}
  
  def login     
    wrap_action_handle_errors(params[:rets_info]) do |metadata|
      resources = [];
      metadata.GetAllResources.each do |resource| 
        resources.push(get_resource_info(metadata, resource))
      end
      {:server_info => get_server_info(metadata), :resources => resources}
    end
  end
  
  def fields
    wrap_action_handle_errors(params[:rets_info]) do |metadata|          
      aClass = metadata.getClass(params[:resource], params[:class])            
      lookups =  {}
      metadata.all_lookups(params[:resource]).each{|lookup| lookups[lookup.lookup_name] = lookup}      
      metadata.all_tables(aClass).collect do |table|
        result = {:system_name => table.system_name, :standard_name => table.standard_name,
          :short_name => table.GetStringAttribute("ShortName", ""), :long_name => table.GetStringAttribute("LongName", ""),
          :required => table.GetStringAttribute("Required", "0"), :type => get_data_type_string(table.get_data_type), 
          :display_type => get_display_type_string(table.get_data_type),
          :searchable => table.IsSearchable()}
        table.lookup_name.blank? ? result : result.merge(:lookups => get_lookup_info(metadata, lookups[table.lookup_name]))                
      end
    end
  end
  
  def dmql
    render :text => build_dmql(params), :content_type => 'text/plain'
  end
  
  def simple
    results = {}
    results[:rets_info] = params[:rets_info].symbolize_keys
    results[:resource] = params[:resource]
    results[:class] = params[:class]
    results[:select] = params[:select]
    results[:dmql] = build_dmql(params)
    render :text => results.to_yaml, :content_type => 'text/yaml'
  end
  
  private #Internal methods, not actions
  
  def build_dmql(params)    
    groups = params[:groups]    
    if(groups != nil && !groups.empty?)
      return build_group(groups.last, groups)
    else 
      return ""
    end
  end
  
  def build_group(group, groups)
    terms = group[:terms].collect {|term|
      if(term['type'] == 'group') 
        build_group(groups[term['field'].to_i - 1], groups)
      else 
        build_term(term)
      end
    }.join(group[:operator]) 
    
    if(group[:terms].size > 1) 
      return "(#{terms})"
    else
      return terms;
    end
    
  end
  
  def build_term(term)
    dmql = term['field']+term['operator']
    if(term['type'] == 'lookup')
      dmql = dmql.sub("%", term['value'].join(','))
    else
      term['value'].each do |value| 
        dmql = dmql.sub("%", value)
      end
    end
    
    return "(#{dmql})"
    
  end
  
  def wrap_action_handle_errors(rets_info)
    begin        
      execute_metadata_action(rets_info) do |metadata|
        render :json => yield(metadata)
      end       
    rescue RetsLoginError => e      
      render :json => e.session_context.merge({:message => e.message}), :status => 500
    rescue Exception => e
      render :json => {:message => e.message}, :status => 500
    end      
  end
  
  def get_server_info(metadata)    
    system = metadata.system
    {:system_id => system.system_id, :description => system.system_description, :comment => system.comments}
  end
  
  def get_resource_info(metadata, resource) 
    
    classes = []
    metadata.GetAllClasses(resource.resource_id).each do |aClass|
      classes.push(get_class_info(aClass))
    end    
    
    {
      :system_name => resource.resource_id,      
      :standard_name => resource.standard_name,
      :visible_name => resource.GetStringAttribute("VisibleName", ""),
      :classes => classes
    }
  end
  
  def get_class_info(aClass)
    {
      :system_name => aClass.class_name,      
      :standard_name => aClass.standard_name,
      :visible_name => aClass.GetStringAttribute("VisibleName", "")
    }
  end
  
  def get_lookup_info(metadata, lookup) 
    metadata.all_lookup_types(lookup).collect do |lookup_type|
      {:value => lookup_type.value, :long => lookup_type.long_value, :short => lookup_type.short_value}
    end
  end
end
